/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is COID coidgen tool.
 *
 * The Initial Developer of the Original Code is
 * PosAm.
 * Portions created by the Initial Developer are Copyright (C) 2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Robo Strycek
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */



#include <stdio.h>
#include <string.h>
#include <memory.h>

#include "coidgen.h"





namespace coid {




const char * STR_skip_args[] = {
	"const"
};
const uint STR_skip_args_size = sizeof(STR_skip_args)/sizeof(char*);


NAME_FLAGS STR_remove_types[] = {
	{"operator", NAME_FLAGS::fappend_name}, {"friend", NAME_FLAGS::ferror}, {"virtual", 0},
	{"static", NAME_FLAGS::ferror}, 	//, {"__declspec", 0}
};
const uint STR_remove_types_size = (sizeof(STR_remove_types) / sizeof(NAME_FLAGS));


KEYWORDS STR_templates[] = {
	{"%name%", sizeof("%name%")-1, 1, 0},
	{"%shortname%", sizeof("%shortname%")-1, 2, 0},
    {"%info%", sizeof("%info%")-1, 3, 0},
	{"%service_header_name%", sizeof("%service_header_name%")-1, 4, 0},
	{"%client_header_name%", sizeof("%client_header_name%")-1, 5, 0},
    {"%derived_from%", sizeof("%derived_from%")-1, 6, 0},
	{"%fnc_count%", sizeof("%fnc_count%")-1, 10, 0},
	{"%fnc_max_count%", sizeof("%fnc_max_count%")-1, 11, 0},
	{"%method_flags_max_count%", sizeof("%method_flags_max_count%")-1, 12, 0},
	{"%_version_%", sizeof("%_version_%")-1, 20, 0},
	{"%version%", sizeof("%version%")-1, 21, 0},
	{"%comm_version%", sizeof("%comm_version%")-1, 22, 0},
	{"%coid_version%", sizeof("%coid_version%")-1, 23, 0},
	{"%flags%", sizeof("%flags%")-1, 50, 0},
	{"%dependencies%", sizeof("%dependencies%")-1, 60, 0},
	{"%class_or_struct%", sizeof("%class_or_struct%")-1, 80, 0},
    {"%namespace%", sizeof("%namespace%")-1, 81, 0},
	{"%acceptor_port%", sizeof("%acceptor_port%")-1, 90, 0},
	{"%fnc_method_flags%", sizeof("%fnc_method_flags%")-1, 100, 0},
	{"%empty_method_set_start%", sizeof("%empty_method_set_start%")-1, 110, 0},
	{"%empty_method_set_end%", sizeof("%empty_method_set_end%")-1, 111, 0},
	{"%declare_coid_flags_if_nonzero%", sizeof("%declare_coid_flags_if_nonzero%")-1, 116, 0},
	{"%coid_throw_function%", sizeof("%coid_throw_function%")-1, 117, 0},
	{"%fnc_client_table%", sizeof("%fnc_client_table%")-1, 200, 0},
	{"%mexestream%", sizeof("%mexestream%")-1, 210, 0},

	/// dispatch.cpp
	{"%fnc_id_name%", sizeof("%fnc_id_name%")-1, 1000, 0},
	{"%fnc_get_params%", sizeof("%fnc_get_params%")-1, 1010, 0},
    {"%fnc_get_params_meta%", sizeof("%fnc_get_params_meta%")-1, 1015, 0},
	{"%fnc_log%", sizeof("%fnc_log%")-1, 1020, 0},
	{"%fnc_log_output%", sizeof("%fnc_log_output%")-1, 1021, 0},
	{"%fnc_call%", sizeof("%fnc_call%")-1, 1030, 0},
	{"%fnc_get_results%", sizeof("%fnc_get_results%")-1, 1040, 0},
	{"%fnc_delete_tmp_objects%", sizeof("%fnc_delete_tmp_objects%")-1, 1050, 0},


	/// client.cpp
	{"%fnc_client_body%", sizeof("%fnc_client_body%")-1, 2000, 0},
	{"%fnc_client_retval_declaration%", sizeof("%fnc_client_retval_declaration%")-1, 2010, 0},
	{"%fnc_client_set_error_ret_value%", sizeof("%fnc_client_set_error_ret_value%")-1, 2020, 0},
	{"%fnc_client_return%", sizeof("%fnc_client_return%")-1, 2100, 0},
	{"%fnc_client_return_error%", sizeof("%fnc_client_return_error%")-1, 2101, 0},
    {"%fnc_client_return_cc%", sizeof("%fnc_client_return_cc%")-1, 2102, 0},
	{"%fnc_client_shared_params%", sizeof("%fnc_client_shared_params%")-1, 2200, 0},

	{"%ib_ret_val_name%", sizeof("%ib_ret_val_name%")-1, 4000, 0},
	{"%ib_open_service1%", sizeof("%ib_open_service1%")-1, 4010, 0},
	{"%ib_open_service2%", sizeof("%ib_open_service2%")-1, 4020, 0},
	{"%open_service_arg_name%", sizeof("%open_service_arg_name%")-1, 4030, 0},
	{"%open_service_client_name%", sizeof("%open_service_client_name%")-1, 4040, 0},
	{"%ib_method_args%", sizeof("%ib_method_args%")-1, 4050, 0},
	{"%ib_method_fetch_args%", sizeof("%ib_method_fetch_args%")-1, 4060, 0},
	{"%ib_method_call%", sizeof("%ib_method_call%")-1, 4100, 0}
};
const uint STR_templates_size = sizeof(STR_templates)/sizeof(KEYWORDS);


KEYWORDS STR_options[] = {
	{"acceptor_port", 0, CLASS::foption_read_info, UMAX32},		/// position matters !
	{"acceptor_bound_session", 0, CLASS::facceptor_bound_session, UMAX32},
	{"not_autonomous", 0, 0, 0},
	{"bindable", 0, CLASS::fbindable, ~CLASS::fautonomous},
	//{"shared", 0, CLASS::fshared, ~CLASS::fautonomous},
	{"direct", 0, CLASS::fallowdirect, UMAX32},
	{"interprocess", 0, CLASS::fallowinterprocess, UMAX32},
	{"remote", 0, CLASS::fallowremote, UMAX32},
	{"nolog_system_calls", 0, CLASS::fnolog_syscalls, UMAX32},
	{"nolog", 0, CLASS::fnolog, UMAX32},
};
const uint STR_options_size = sizeof(STR_options)/sizeof(KEYWORDS);


/// shortest strings --> end of list
KEYWORDS g_ARG_keywords[] = {
		/// must be first
	{STR_net_count, sizeof(STR_net_count) - 1, ARG::fptr_count, UMAX32},
		/// must be second
	{STR_net_openservice, sizeof(STR_net_openservice) - 1, ARG::fopen_service | ARG::finout | ARG::fnolog,
                                                         ~(ARG::fin | ARG::fout | ARG::ffetch | ARG::faccount)},
		/// must be 3.
	{STR_net_remap, sizeof(STR_net_remap) - 1, 0, UMAX32},
		/// must be 4.
	{STR_net_map, sizeof(STR_net_map) - 1, 0, UMAX32},

	{STR_net_malloc, sizeof(STR_net_malloc) - 1, ARG::fmalloc, UMAX32},
	{STR_net_inout, sizeof(STR_net_inout) - 1, ARG::finout, ~(ARG::fin)},
	{STR_net_fetch, sizeof(STR_net_fetch) - 1, ARG::ffetch, ~(ARG::fin | ARG::finout)},
	{STR_net_nolog, sizeof(STR_net_nolog) - 1, ARG::fnolog, UMAX32},
	{STR_net_log, sizeof(STR_net_log) - 1, 0, ~ARG::fnolog},
	{STR_net_ptr, sizeof(STR_net_ptr) - 1, ARG::fnet_ptr, UMAX32},
	{STR_net_in, sizeof(STR_net_in) - 1, ARG::fin, UMAX32},
	{STR_net_out, sizeof(STR_net_out) - 1, ARG::fout, ~(ARG::fin | ARG::finout)},
	{STR_net_account, sizeof(STR_net_account) - 1, ARG::faccount, UMAX32}
};
const uint g_ARG_keywords_size = sizeof(g_ARG_keywords)/sizeof(KEYWORDS);



KEYWORDS STR_special_functions[] = {
	{"accept_connect", 0, CLASS::accept_connect, 0},
	{"accept_connect_shared", 0, CLASS::accept_connect_shared, 0},
	{"accept_connect_auto", 0, CLASS::accept_connect_auto, 0},
	{"accept_net_connections", 0, CLASS::accept_net_connections, 0},

	{"accept_destroy", 0, CLASS::accept_destroy, 0},
	{"accept_startup_params", 0, CLASS::accept_startup_params, 0},
	{"accept_command", 0, CLASS::accept_command, 0},
	{"accept_spawn", 0, CLASS::accept_spawn, 0},
	{"accept_echo", 0, CLASS::accept_echo, 0}
};
const uint STR_special_functions_size = sizeof(STR_special_functions)/sizeof(KEYWORDS);










char * read_file( const char * filename, uint * size )
{
	FILE * f = fopen( filename, "rb" );
	if(!f) return NULL;
	fseek( f, 0, SEEK_END );
	uint s = ftell( f );
	if(size) *size = s;

	fseek( f, 0, SEEK_SET );
	char * p = new char[s + 1];
	if(s) fread( p, s, 1, f );
	fclose( f );
	p[s] = 0;

	return p;
}





char * replace_char( char * ptr, char c1, char c2 )
{
	for( char * p = ptr; *p; p++ )
		if( *p == c1 ) *p = c2;

	return ptr;
}




char * prev_word( char * start, char * end )
{
	char * p = end;
	while( p > start && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') )
		*p-- = 0;

	while( p > start && (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != '&' && *p != '*') )
		p--;

	if( p > start && p != end ) p++;

	return p;
}




char * next_word( char * ptr )
{
	size_t offset = strcspn( ptr, " \t\r\n" );
	if( ptr[offset] == 0 )
		return NULL;
	return str_trim( ptr + offset + 1 );
}



char * str_trim( char * ptr )
{
	while( *ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n' )
		ptr++;

	char * p = ptr + strlen( ptr );
	while( p > ptr && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == 0) )
		*p-- = 0;

	return ptr;
}


int get_line_number( const char * p1, const char * p2 )
{
	int line = 1;
	for( ; p1 < p2; line++, p1++ )
		if( *p1 == '\n' ) line++;

	return line;
}



char * str_count_chr( const char * src, char c1, char c2, int count )
{
	for( ; *src; src++ ) {
		if( *src == c1 ) count++;
		else if( *src == c2 ) count--;
		if( count == 0 ) return (char *) src;
	}

	return 0;
}


const char * str2chr( const char * src, char c1, char c2 )
{
	const char * p = strchr( src, c1 );
	if(!p) return strchr( src, c2 );

	for( ; src < p - 1; src++ ) {
		if( *src == c2 )
			return (char *) src;
	}

	return p;
}


const char * str2str( const char * src, const char * p1, const char * p2, uint size2 )
{
	const char * p = strstr( src, p1 );
	if(!p) return strstr( src, p2 );

	for( ; src < p - size2; src++ ) {
		if( *src == *p2 && strncmp(src, p2, size2) == 0 )
			return (char *) src;
	}

	return p;
}



char * remove_string( char * ptr, const char * what )
{
	ints size = strlen( what );
	char * p = strstr( ptr, what );
	if(p) {
		char * p_src = p + size;
		char * p_dest = p;
		memmove( p_dest, p_src, strlen(p_src) + 1 );
	}
	return p;
}



char * remove_word( char * ptr, const char * what )
{
	ints size = strlen( what );
	char * p = strstr( ptr, what );
	if( p && (p[size] == ' ' || p[size] == '\t' || p[size] == '\r' || p[size] == '\n' || p[size] == ')' || p[size] == ',') )
	{
		char * p_src = p + size;
		char * p_dest = p;
		memmove( p_dest, p_src, strlen(p_src) + 1 );
	}
	return p;
}



char * remove_part_of_string( char * start, const char * end )
{
	memmove( start, end, strlen(end) + 1 );
	return start;
}




} // namespace coid

